/**
 * Java8通过Function函数获取字段名称(获取实体类的字段名称)
 *
 * @Author: qi
 * @Date: 2022/4/27 16:59
 */
package com.cmc.cloud.cmclink.doc.util.so;

import com.cmc.cloud.cmclink.doc.vo.sovo.sovo.SoCreateReqVO;
import io.swagger.v3.oas.annotations.media.Schema;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;

public class ColumnUtil {

    /**
     * 使Function获取序列化能力
     */
    public interface SuperFunction<T, R> extends Function<T, R>, Serializable {
    }

    /**
     * 获取实体类的字段名称
     */
    public static <T> String getFieldName(SuperFunction<T, ?> fn) {
        SerializedLambda serializedLambda = getSerializedLambda(fn);
        // 从lambda信息取出method、field、class等
        String fieldName = serializedLambda.getImplMethodName().substring("get".length());
        fieldName = fieldName.replaceFirst(fieldName.charAt(0) + "", (fieldName.charAt(0) + "").toLowerCase());
        Field field;
        try {
            field = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredField(fieldName);
        } catch (ClassNotFoundException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        // 从field取出字段名，可以根据实际情况调整
        Schema tableField = field.getAnnotation(Schema.class);
        if (tableField != null && tableField.description().length() > 0) {
            return tableField.description();
        }
        return "";
    }

    private static <T> SerializedLambda getSerializedLambda(SuperFunction<T, ?> fn) {
        // 从function取出序列化方法
        Method writeReplaceMethod;
        try {
            writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        // 从序列化方法取出序列化的lambda信息
        boolean isAccessible = writeReplaceMethod.isAccessible();
        writeReplaceMethod.setAccessible(true);
        SerializedLambda serializedLambda;
        try {
            serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        writeReplaceMethod.setAccessible(isAccessible);
        return serializedLambda;
    }

    public static void main(String[] args) {
        System.out.println(ColumnUtil.getFieldName(SoCreateReqVO::getBookingParty));
    }

}
